#ifndef _RECYCLING_POOL_INC_
#define _RECYCLING_POOL_INC_

#include <vector>

template <typename TPoolObj> class RecyclingPool
{
public:	
	RecyclingPool(int iNumElements, bool bMustNew=true)
	{
		m_iNumElements = iNumElements;
		m_bMustNew = bMustNew;

		m_bAlive = new bool[iNumElements];
		m_aElements = new TPoolObj[iNumElements];

		for(int q=0; q < iNumElements; q++) 
		{
			m_bAlive[q] = false;
		}

		m_iUsedElements = 0;
		m_iLastNew = 0;
	}

	virtual ~RecyclingPool() 
	{
		delete[] m_bAlive;
		delete[] m_aElements;
	}

	TPoolObj * GetFreeObject()
	{
		// assert that we have space for this one
		if (GetNumFreeElements() < 1) 
		{
			if(m_bMustNew && m_iNumElements>0)
			{
				int maybeFirstNew = m_iLastNew+1;
				if (maybeFirstNew >= m_iNumElements) 
				{
					maybeFirstNew = 0;
				}
				FreeObject(maybeFirstNew);
			}
			else
			{				
				return 0;
			}		
		}

		// find first element not in use.  as an optimization, we start at
		// the position that was allocated last, in the hopes that the next position
		// will be free.

		int i = m_iLastNew;
		for (int q=0; q < m_iNumElements; q++) 
		{
			if (!m_bAlive[i]) 
			{
				// we've found our free spot!  use it!
				break;
			}
			else 
			{
				i++; 
				if (i >= m_iNumElements) 
					i = 0;
			}
		}

		if (m_bAlive[i]) 
		{
		  // huh? if we got here, there are no free elements in the list... yet 
		  // GetNumFreeElements didn't tell us that in the beginning.  Logic error.
		  //assert(false && "TPoolObj::GetFreeObject(): internal logic error.");
		  return 0;
		}

		// clear it,  TPoolObj class must has Reset()
		m_aElements[i].Reset();

		// increment used count
		m_iUsedElements++;
		m_bAlive[i] = true;
		m_iLastNew = i;
    
		// return it
		return(&m_aElements[i]);
	}

	bool FreeObject(int index)
	{
		if (index < 0 || index >= m_iNumElements || !m_bAlive[index]) 
		{
			return false;
		}
		// don't actually delete element at index;
		// just mark it free.
		m_bAlive[index] = false;
		m_iUsedElements--;
		return true;
	}

	bool FreeObject(TPoolObj *elem)
	{
		if (m_iUsedElements == 0) 
		{
			return false;
		}
		
		int iElem = reinterpret_cast<int>(elem);
		iElem -= reinterpret_cast<int>(&m_aElements[0]);
		int index = iElem / sizeof(TPoolObj);
		
		if (index < 0 || index >= m_iNumElements || !m_bAlive[index]) 
		{
			return false ;
		}
		
		m_bAlive[index] = false;
		m_iUsedElements--;		
		return true;
	}

	int GetNumFreeElements() { return(m_iNumElements-GetNumUsedElements()); }
	int GetNumUsedElements() { return(m_iUsedElements); }

	int GetTotalElements() { return(m_iNumElements); }

	TPoolObj &GetAt(int index) { return(m_aElements[index]); }
	bool IsAlive(int index) { return(m_bAlive[index]); }

	void FreeAll()
	{
		for (int q=0; q < m_iNumElements; q++) 
		{
			m_bAlive[q] = false;
		}
		m_iUsedElements = 0;
		m_iLastNew = 0;
	}

	int GetLastNewIndex() { return m_iLastNew; }

protected:
	int m_iNumElements;
	int m_iUsedElements;
	TPoolObj *m_aElements; 
	bool *m_bAlive;
	int m_iLastNew;	
	bool m_bMustNew;

private:
	RecyclingPool()
	{
	}	
};

#endif //_RECYCLING_POOL_INC_